package com.util;

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: hdu_huang
 * @Date: 2018/10/26 18:47
 */
public class FileUtil {

    public static final char DIR_SEPARATOR_UNIX = '/';
    public static final char DIR_SEPARATOR_WINDOWS = '\\';
    public static final char DIR_SEPARATOR = File.separatorChar;
    public static final String LINE_SEPARATOR_UNIX = "\n";
    public static final String LINE_SEPARATOR_WINDOWS = "\r\n";
    public static final String LINE_SEPARATOR = DIR_SEPARATOR_WINDOWS == DIR_SEPARATOR ? LINE_SEPARATOR_WINDOWS : LINE_SEPARATOR_UNIX;
    private static final int DEFAULT_BUFFER_SIZE = 4096;


    public static String toHexString(byte[] source) {
        StringBuilder result = new StringBuilder(source.length * 2);
        for (byte b : source) {
            result.append(Integer.toHexString((b & 0xf0) >>> 4));
            result.append(Integer.toHexString(b & 0x0f));
        }
        return result.toString();
    }

    /**
     * @author hdu_huang
     * @date 2021/7/21
     * @desc 获取 md5/sha-1/sha-256/sha-384/sha-512 编码
     */
    public static String getDigestString(byte[] source, String digestMethod) {

        try {
            MessageDigest md = MessageDigest.getInstance(digestMethod);
            byte[] digest = md.digest(source);
            return toHexString(digest);
        } catch (Exception ignored) {
            return null;
        }
    }

    public static String getMD5String(String source) {
        byte[] bytes = source.getBytes(StandardCharsets.UTF_8);
        return getMD5String(bytes);
    }

    public static String getMD5String(byte[] source) {

        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(source);
            return toHexString(digest);
        } catch (Exception ignored) {
            return null;
        }
    }


    /**
     * @author hdu_huang
     * @date 2018/9/18
     * @funs 小于500M
     */

    public static String getFileMD5(String path) {

        try {
            byte[] bytes = Files.readAllBytes(Paths.get(path));
            return getMD5String(bytes);
        } catch (IOException ignored) {
            return null;
        }
    }

    /**
     * @author hdu_huang
     * @date 2021/7/21
     * @desc 流式读取文件[大文件]  MD5
     */
    public static String getFileMD5ByStream(String path) {

        byte[] buffer = new byte[1024 * 16]; //16k
        int len;
        try {
            InputStream inputStream = Files.newInputStream(Paths.get(path));
            MessageDigest md = MessageDigest.getInstance("MD5");
            while ((len = inputStream.read(buffer)) > 0) {
                md.update(buffer, 0, len);
            }
            return toHexString(md.digest());

        } catch (Exception ignored) {
            return null;
        }
    }

    //获取classpath路径的文件流    eg:static/index.html   application.properties     @see ClassPathResource
    //fatjar是LaunchedURLClassLoader而不是SystemClassLoader    所以应该当前类加载器
    public static InputStream getClassPathFileInputStream(String classpathFilePath) throws IOException {
        ClassLoader classLoader = FileUtil.class.getClassLoader();
        return classLoader.getResourceAsStream(classpathFilePath);
    }


    /**
     * @author hdu_huang
     * @date 2018/10/26
     * @funs InputStream -> Stream<Stream>   try-with-resource or Stream.close
     */

    public static Stream<String> lines(InputStream inputStream) throws IOException { //java11 inputStream.transferTo

        return lines(inputStream, StandardCharsets.UTF_8.name());
    }

    // StandardCharsets.UTF_8
    public static Stream<String> lines(InputStream inputStream, String charsetName) throws IOException { //java11 inputStream.transferTo

        Charset charset;
        if (charsetName != null) {
            charset = Charset.forName(charsetName);
        } else {
            charset = Charset.defaultCharset();
        }

        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset));
        return br.lines().onClose(asUncheckedRunnable(br));
    }

    // 返回 Runnable 的方法, lambda
    private static Runnable asUncheckedRunnable(Closeable c) {
        return () -> {
            try {
                c.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        };
    }

    public static List<String> toList(InputStream inputStream) throws Exception {
        return lines(inputStream).collect(Collectors.toList());
    }


    //StandardCharsets.UTF_8   Charset.defaultCharset()  "UTF-8"
    public static String toString(InputStream inputStream) throws IOException {
        return toString(inputStream, StandardCharsets.UTF_8.name());
    }

    // 不一定是 "\r\n"  linux  此方法不准确
    @Deprecated
    private static String toString1(InputStream inputStream, String charsetName) throws Exception {
        return lines(inputStream, charsetName).collect(Collectors.joining("\r\n"));
    }

    //IOUtils.toString
    public static String toString(InputStream inputStream, String charsetName) throws IOException {

        if (inputStream == null) {
            return null;
        }

        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[1024 * 4]; //4k
        int len;

        InputStreamReader reader = new InputStreamReader(inputStream, charsetName);

        while ((len = reader.read(buffer)) > 0) {
            builder.append(buffer, 0, len);
        }

        reader.close();
        inputStream.close();

        return builder.toString();
    }


    //common-io IOUtils,  FIleUtils
    //nacos-client  FileUtil
    public static void main(String[] args) throws Exception {

        String fileUrl = "dream.db";

        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        URL url = classLoader.getResource(fileUrl);
        InputStream inputStream = classLoader.getResourceAsStream(fileUrl); //通过classLoader

        long count = lines(inputStream).count();

        System.out.println(count);

    }

}
